package jpal.collect;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Collections;
import java.util.Iterator;
import java.util.ListIterator;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;

/**
 * Static utility methods which operate on or return {@link Sortedlist}s.
 * 
 * @author Zhenya Leonov
 */
final public class Sortedlists {

	private Sortedlists() {
	}

	/**
	 * Returns the index of the first occurrence in the specified sorted-list of
	 * an element which satisfies the given predicate, or -1 if there is no such
	 * element.
	 * <p>
	 * Note: If the specified sorted-list allows {@code null} elements the given
	 * predicate must be able to handle {@code null} inputs to avoid a
	 * {@code NullPointerException}.
	 * 
	 * @param sortedlist
	 *            the specified sorted-list
	 * @param predicate
	 *            the given predicate
	 * @return the index of the first occurrence in the specified sorted-list of
	 *         an element which satisfies the given predicate, or -1 if there is
	 *         no such element
	 */
	public static <E> int indexOf(final Sortedlist<E> sortedlist,
			final Predicate<? super E> predicate) {
		checkNotNull(sortedlist);
		checkNotNull(predicate);
		final ListIterator<E> e = sortedlist.listIterator();
		while (e.hasNext())
			if (predicate.apply(e.next()))
				return e.previousIndex();
		return -1;
	}

	/**
	 * Returns the index of the last occurrence in the specified
	 * sorted-sorted-list of an element which satisfies the given predicate, or
	 * -1 if there is no such element.
	 * <p>
	 * Note: If the specified sorted-list allows {@code null} elements the given
	 * predicate must be able to handle {@code null} inputs as well to avoid a
	 * {@code NullPointerException}.
	 * 
	 * @param sortedlist
	 *            the specified sorted-list
	 * @param predicate
	 *            the given predicate
	 * @return the index of the last occurrence in the specified sorted-list of
	 *         an element which satisfies the given predicate, or -1 if there is
	 *         no such element
	 */
	public static <E> int lastIndexOf(final Sortedlist<E> sortedlist,
			final Predicate<? super E> predicate) {
		checkNotNull(sortedlist);
		checkNotNull(predicate);
		final ListIterator<E> e = sortedlist.listIterator(sortedlist.size());
		while (e.hasPrevious())
			if (predicate.apply(e.next()))
				return e.previousIndex();
		return -1;
	}

	/**
	 * Creates a {@code Treelist} containing the specified initial elements
	 * sorted according to their <i>natural ordering</i>.
	 * 
	 * @param elements
	 *            initial elements
	 * @return a {@code Treelist} containing the specified initial elements
	 *         sorted according to their <i>natural ordering</i>
	 */
	@SuppressWarnings("rawtypes")
	public static <E extends Comparable> Treelist<E> newTreelist(
			final E... elements) {
		checkNotNull(elements);
		final Treelist<E> tl = Treelist.create();
		Collections.addAll(tl, elements);
		return tl;
	}

	/**
	 * Creates a {@code Skiplist} containing the specified initial elements
	 * sorted according to their <i>natural ordering</i>.
	 * 
	 * @param elements
	 *            initial elements
	 * @return a {@code Skiplist} containing the specified initial elements
	 *         sorted according to their <i>natural ordering</i>
	 */
	@SuppressWarnings("rawtypes")
	public static <E extends Comparable> Skiplist<E> newSkiplist(
			final E... elements) {
		checkNotNull(elements);
		final Skiplist<E> sl = Skiplist.create();
		Collections.addAll(sl, elements);
		return sl;
	}

	/**
	 * Creates a {@code Skiplist} containing the specified initial elements
	 * sorted according to their <i>natural ordering</i>.
	 * 
	 * @param elements
	 *            initial elements
	 * @return a {@code Skiplist} containing the specified initial elements
	 *         sorted according to their <i>natural ordering</i>
	 */

	@SuppressWarnings("rawtypes")
	public static <E extends Comparable> Skiplist<E> newSkiplist(
			final Iterator<? extends E> elements) {
		checkNotNull(elements);
		final Skiplist<E> sl = Skiplist.create();
		Iterators.addAll(sl, elements);
		return sl;
	}

	/**
	 * Creates a {@code Skiplist} containing the specified initial elements
	 * sorted according to their <i>natural ordering</i>.
	 * 
	 * @param elements
	 *            initial elements
	 * @return a {@code Skiplist} containing the specified initial elements
	 *         sorted according to their <i>natural ordering</i>
	 */

	@SuppressWarnings("rawtypes")
	public static <E extends Comparable> Treelist<E> newTreelist(
			final Iterator<? extends E> elements) {
		checkNotNull(elements);
		final Treelist<E> treelist = Treelist.create();
		Iterators.addAll(treelist, elements);
		return treelist;
	}

}
